library Dialog uses Table
//==============================================================================
//                    DIALOG SYSTEM BY COHADAR -- v3.1
//                               对话框系统 V3.1
//                                                           作者:COHADAR
//==============================================================================
//
//  作用:
//       * Displaying dialogs the easy way
//            以一种简单的方式显示对话框
//       * Retrieving dialog results the easy way
//          以一种简单的方式检索对话框被点击
//
//  使用:
//       * Dialog is basically a struct wrapper around native dialog
//          对话框总的来说是一种被包装过的本地对话.
//
//       * First create a dialog,
//          第一次创建一个对话框
//            # local Dialog d = Dialog.create(integer data)
//
//         than add a title,
//          然后添加一个标题
//            # call d.SetMessage("Some Text")
//
//         than add couple of buttons
//          然后添加一些按钮
//            #    call d.AddButton("First Button",  HK_A)
//            #    call d.AddButton("Second Button", HK_B)
//            #    call d.AddButton("Third",         HK_C)
//
//         HK_X is a hotkey constant for a button,
//         there are constants for all letters + numbers 0..9
//         hotkeys are not case-sensitive
//            HK_X 是按钮所包含的快捷键,按钮可使用的快捷键包含所有的字母和0-9之间的数字.
//            快捷键是不区分大小写的.
//
//         now add a callback method for your dialog
//            现在为你的对话框添加一个"callback"函数.
//            # call d.AddAction( function SomeFunction )
//         this is the function that will be called when a player presses a button
//            该函数会在玩家按下按钮时被调用.
//
//         And finally show the dialog in one of two ways:
//            最后,以下面两种方式中任意一种方式显示对话框
//            # call d.ShowAll()      // Displays dialog to all human players
//                                         显示对话框给所有非电脑玩家
//            # call d.Show( player ) // Displays dialog to specified player
//                                         显示对话框给特定玩家
//
//         Inside your callback function you can get the clicked Dialog struct like this
//            在你的"callback"函数中,你可以像这样获取被点击的对话框
//               # local Dialog d = Dialog.Get()
//
//           and then use d.GetResult() to get the hotkey of a clicked button
//           并且可以使用"d.GetResult()"来获取被点击按钮的快捷键
//              # d.GetResult()
//
//         You can also use GetTriggerPlayer() to find out witch player pressed the button
//           你也可以使用"GetTriggerPlayer()"来获取是哪个玩家点击的对话框
//            # GetTriggerPlayer()
//
//         When you are done with Dialog you can:
//           当整个过程结束时,你可以:
//            # call d.destroy()  // destroy it completely
//                                    完全销毁该对话框
//            # call d.clear()    // or recycle it
//                                    回收该对话框
//
//  优点:
//       * Extremelly easy to use compared to native dialogs
//            相对于自带的对话框函数,极大的简化了它的使用
//       * It is fool-proof and will warn you if you try to do something stupid
//            该系统极为简单,并且带有错误提醒.
//
//  注意:
//       * Don't release Dialogs before you are sure user has selected something
//         I recommend to never destroy Dialogs,
//         just create them when they are first time called and then show/hide them as needed
//             在你确定使用者按下按钮之前不要释放对话框所占内存,我建议不要销毁对话框,
//            只在第一次使用时创建它们,当需要再次使用时,采用显示/隐藏对话框即可.
//
//  THANKS:
//       * Magentix for finding the triggeraction leak and suggesting clear method
//       * Vexorian for creating Table so I don't have to mess with handles myself
//
//  需要:
//       * Table v3.0 或者更高
//
//  导入:
//       * 创建一个触发器
//       * 转换为自定义文本,清空文本,复制粘贴该库即可.
//
//==============================================================================

globals
    // Dialog button hotkey constants
    constant integer HK_ESC = 512

    constant integer HK_0 = 48
    constant integer HK_1 = 49
    constant integer HK_2 = 50
    constant integer HK_3 = 51
    constant integer HK_4 = 52
    constant integer HK_5 = 53
    constant integer HK_6 = 54
    constant integer HK_7 = 55
    constant integer HK_8 = 56
    constant integer HK_9 = 57

    constant integer HK_A = 65
    constant integer HK_B = 66
    constant integer HK_C = 67
    constant integer HK_D = 68
    constant integer HK_E = 69
    constant integer HK_F = 70
    constant integer HK_G = 71
    constant integer HK_H = 72
    constant integer HK_I = 73
    constant integer HK_J = 74
    constant integer HK_K = 75
    constant integer HK_L = 76
    constant integer HK_M = 77
    constant integer HK_N = 78
    constant integer HK_O = 79
    constant integer HK_P = 80
    constant integer HK_Q = 81
    constant integer HK_R = 82
    constant integer HK_S = 83
    constant integer HK_T = 84
    constant integer HK_U = 85
    constant integer HK_V = 86
    constant integer HK_W = 87
    constant integer HK_X = 88
    constant integer HK_Y = 89
    constant integer HK_Z = 90
endglobals

//===========================================================================
struct Dialog
    private trigger t = null
    private triggeraction a = null
    private dialog  d = null
    private string messageText = ""
    private integer button_count = 0

    private static HandleTable dialogTable
    private static HandleTable buttonTable

    integer data = 0

    static method onInit takes nothing returns nothing
        set Dialog.dialogTable = HandleTable.create() // Table
        set Dialog.buttonTable = HandleTable.create() // Table
    endmethod

    static method create takes nothing returns thistype
        local Dialog this = thistype.allocate()
        set this.t = CreateTrigger()
        set this.d = DialogCreate()
        set Dialog.dialogTable[this.d] = this // Table
        call TriggerRegisterDialogEvent( this.t, this.d )
        return this
    endmethod

    method clear takes nothing returns nothing
        if .a != null then
            call TriggerRemoveAction(.t, .a)
            set .a = null
        endif
        set .messageText = ""
        set .button_count = 0
        call DialogClear(.d)
    endmethod

    method destroy takes nothing returns nothing
        if .a != null then
            call TriggerRemoveAction(.t, .a)
        endif
        call DestroyTrigger(.t)
        call .dialogTable.flush(.d) // Table
        call DialogDestroy(.d)
        call this.deallocate()
    endmethod


    static method Get takes nothing returns Dialog
        return Dialog.dialogTable[GetClickedDialog()] // Table
    endmethod

    method GetCarryData takes nothing returns integer
        return .data
    endmethod

    method SetCarryData takes integer data returns nothing
        set .data=data
    endmethod

    method GetResult takes nothing returns integer
        return .buttonTable[GetClickedButton()] // Table
    endmethod

    method SetMessage takes string messageText returns nothing
        set .messageText = messageText
    endmethod

    method AddButton takes string buttonText, integer hotkey returns nothing
        set .buttonTable[DialogAddButton(.d,  buttonText, hotkey)] = hotkey
        set .button_count = .button_count + 1
    endmethod

    method AddAction takes code actionFunc returns nothing
        if .a != null then
            debug call BJDebugMsg("|c00FF0000Dialog.AddAction: 不能添加更多动作")
        else
            set .a = TriggerAddAction( .t, actionFunc )
        endif
    endmethod

    method Show takes player whichPlayer returns nothing
        if .a == null then
            debug call BJDebugMsg("|c00FF0000Dialog.Show: 没有添加点击后的动作")
        endif
        if .button_count == 0 then
            debug call BJDebugMsg("|c00FF0000Dialog.Show: 没有添加按钮")
        else
            // message must be set before every display because of some bug.
            call DialogSetMessage( .d, .messageText )
            call DialogDisplay(whichPlayer, .d, true)
        endif
    endmethod

    method ShowAll takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i>=12 // maximum of human players is 12
            if GetPlayerController(Player(i)) == MAP_CONTROL_USER then
            if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING then
                call .Show(Player(i))
            endif
            endif
            set i = i + 1
        endloop
    endmethod

    method Hide takes player whichPlayer returns nothing
        call DialogDisplay(whichPlayer, .d, false)
    endmethod

    method HideAll takes nothing returns nothing
        local integer i = 0
        loop
            exitwhen i>=12 // maximum of human players is 12
                call .Hide(Player(i))
            set i = i + 1
        endloop
    endmethod

endstruct

endlibrary